﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
using VBFOOL.MediaPlayer.Core.Interface;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Documents;
using System.IO.IsolatedStorage;
using System.Text.RegularExpressions;
namespace TestPhone
{
    public class SRTSubtitleController : SubtitleController
    {
        public SRTSubtitleController(Panel Container, ISubtitleReader reader)
            : base(Container, reader)
        {
            FontSize = 30;
            if (IsolatedStorageSettings.ApplicationSettings.Contains("FontScale"))
            {
                var FontScale = (double)IsolatedStorageSettings.ApplicationSettings["FontScale"];
                FontSize *= FontScale;
            }
        }

        public Brush Foreground { get; set; }
        public Brush Outline { get; set; }
        public double FontSize { get; set; }

        public override FrameworkElement NewSubtitleItem(SubtitleItem item)
        {
            TextBlock txtSubtitle = new TextBlock()
            {
                Text = item.Text,
                HorizontalAlignment = System.Windows.HorizontalAlignment.Center,
                TextAlignment = TextAlignment.Center,
                FontSize = FontSize,
                Foreground = Foreground ?? new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.White),
                TextWrapping = System.Windows.TextWrapping.Wrap,
                MaxWidth = Container.ActualWidth,
                IsHitTestVisible = false
            };
            txtSubtitle.UpdateLayout();
            TextBlock txtSubtitleBack = new TextBlock()
            {
                Text = item.Text,
                HorizontalAlignment = System.Windows.HorizontalAlignment.Center,
                TextAlignment = TextAlignment.Center,
                FontSize = FontSize,
                Foreground = Outline ?? new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Black),
                TextWrapping = System.Windows.TextWrapping.Wrap,
                MaxWidth = Container.ActualWidth,
                IsHitTestVisible = false
            };
            txtSubtitleBack.UpdateLayout();

            WriteableBitmap bmp = new WriteableBitmap((int)txtSubtitle.ActualWidth + 2, (int)txtSubtitle.ActualHeight + 2);
            bmp.Render(txtSubtitleBack, new TranslateTransform() { X = 0, Y = 1 });
            bmp.Render(txtSubtitleBack, new TranslateTransform() { X = 2, Y = 1 });
            bmp.Render(txtSubtitleBack, new TranslateTransform() { X = 1, Y = 0 });
            bmp.Render(txtSubtitleBack, new TranslateTransform() { X = 1, Y = 2 });
            bmp.Render(txtSubtitle, new TranslateTransform() { X = 1, Y = 1 });
            bmp.Invalidate();
            Image gd = new Image()
            {
                Source = bmp,
                Stretch = System.Windows.Media.Stretch.None,
                HorizontalAlignment = System.Windows.HorizontalAlignment.Center,
                VerticalAlignment = System.Windows.VerticalAlignment.Bottom
            };

            Container.Children.Add(gd);
            Storyboard sb = new Storyboard();
            sb.Duration = new Duration(item.Duration);
            sb.AutoReverse = false;
            sb.FillBehavior = FillBehavior.HoldEnd;
            sb.Completed += (o, e) =>
            {
                Container.Children.Remove(gd);
                gd.Source = null;
            };
            sb.Begin();

            return gd;
        }
    }

    public class ASSSubtitleController : SubtitleController
    {
        public ASSSubtitleController(Panel Container, ISubtitleReader reader)
            : base(Container, reader)
        {
            doc.Load(reader.SubtilteHeader);
            if (IsolatedStorageSettings.ApplicationSettings.Contains("FontScale"))
            {
                FontScale = (double)IsolatedStorageSettings.ApplicationSettings["FontScale"];
            }
        }
        ASSReader.SubtitleDocument doc = new ASSReader.SubtitleDocument();
        double FontScale = 1.0;
        public static HorizontalAlignment GetHorizontalAlignment(int Alignment)
        {
            var i = (Alignment - 1) % 3;
            switch (i)
            {
                case 0:
                    return HorizontalAlignment.Left;
                case 1:
                    return HorizontalAlignment.Center;
                case 2:
                    return HorizontalAlignment.Right;
                default:
                    return HorizontalAlignment.Stretch;
            }
        }
        public static VerticalAlignment GetVerticalAlignment(int Alignment)
        {
            var i = (Alignment - 1) / 3;
            switch (i)
            {
                case 0:
                    return VerticalAlignment.Bottom;
                case 1:
                    return VerticalAlignment.Center;
                case 2:
                    return VerticalAlignment.Top;
                default:
                    return VerticalAlignment.Stretch;
            }
        }
        public static Color GetColor(string ColorString)
        {
            var c = ColorString.Replace("&H", "");
            var cv = uint.Parse(c, System.Globalization.NumberStyles.HexNumber);
            byte[] b = BitConverter.GetBytes(cv);
            var alpha = 255 - b[3];
            return Color.FromArgb((byte)alpha, b[0], b[1], b[2]);
        }
        void ReDraw(WriteableBitmap Target, string ColorBack, string ColorFore)
        {
            var c1 = GetColor(ColorBack);
            var c2 = GetColor(ColorFore);
            for (int i = 0; i < Target.Pixels.Length; i++)
            {
                int b = Target.Pixels[i];
                if (b != 0)
                {
                    byte[] b2 = BitConverter.GetBytes(b);
                    if (b2[0] == 0)
                    {
                        b2[0] = c1.B;
                        b2[1] = c1.G;
                        b2[2] = c1.R;
                    }
                    else
                    {
                        b2[0] = c2.B;
                        b2[1] = c2.G;
                        b2[2] = c2.R;
                    }
                    b = BitConverter.ToInt32(b2, 0);
                }
                Target.Pixels[i] = b;
            }
        }
        SolidColorBrush ForeBrush = new SolidColorBrush(Colors.White);
        SolidColorBrush BackBrush = new SolidColorBrush(Colors.Black);
        public override FrameworkElement NewSubtitleItem(SubtitleItem item)
        {
            var ev = doc.GetEventItem2(item.Text);
            var st = doc.Styles[ev.Style.Trim(' ', '*')];
            if (st == null)
            {
                st = doc.Styles[0];
            }
            var hg = GetHorizontalAlignment(st.Alignment);
            var vg = GetVerticalAlignment(st.Alignment);
            var ha = doc.Info.PlayResX > 0 ? Container.ActualWidth / doc.Info.PlayResX : 1;
            var va = doc.Info.PlayResY > 0 ? Container.ActualHeight / doc.Info.PlayResY : 1;
            TextBlock txtSubtitle = new TextBlock()
            {
                TextWrapping = System.Windows.TextWrapping.Wrap,
                TextAlignment = System.Windows.TextAlignment.Center,
                MaxWidth = Container.ActualWidth,
                //Foreground = ForeBrush,
                IsHitTestVisible = false
            };
            //txtSubtitle.UpdateLayout();
            TextBlock txtSubtitleBack = new TextBlock()
            {
                TextAlignment = System.Windows.TextAlignment.Center,
                TextWrapping = System.Windows.TextWrapping.Wrap,
                MaxWidth = Container.ActualWidth,
                //Foreground = BackBrush,
                IsHitTestVisible = false
            };
            //txtSubtitleBack.Text = ev.Text;

            //txtSubtitleBack.UpdateLayout();
            double lh = 1;
            //if (st.Outline > 0)
            //{
            //    lh = st.Outline;
            //}
            Thickness tk = new Thickness();
            double l1 = ev.MarginL > 0 ? ev.MarginL : st.MarginL;
            double r1 = ev.MarginR > 0 ? ev.MarginR : st.MarginR;
            double v1 = ev.MarginV > 0 ? ev.MarginV : st.MarginV;
            switch (vg)
            {
                case VerticalAlignment.Bottom:
                    tk = new Thickness(l1, 0, r1, v1);
                    break;
                case VerticalAlignment.Stretch:
                case VerticalAlignment.Center:
                    tk = new Thickness(l1, 0, r1, 0);
                    break;
                case VerticalAlignment.Top:
                    tk = new Thickness(l1, v1, r1, 0);
                    break;
                default:
                    break;
            }
            Image gd = new Image()
            {
                // Source = bmp,
                Margin = tk,
                //Stretch = System.Windows.Media.Stretch.None,
                HorizontalAlignment = hg,
                VerticalAlignment = vg
            };
            Storyboard sb = new Storyboard();
            sb.Duration = new Duration(item.Duration);
            sb.AutoReverse = false;
            sb.FillBehavior = FillBehavior.Stop;
            ev.Text = ev.Text.Replace(@"\h", " ");
            var strs = ev.Text.Split(new[] { @"\n", @"\N" }, StringSplitOptions.None);
            foreach (var str in strs)
            {
                FontWeight fw = FontWeights.Normal;
                switch (st.Bold)
                {
                    case 1:
                        fw = FontWeights.Bold;
                        break;
                    default:
                        break;
                }
                FontStyle fs = (st.Italic != 0) ? FontStyles.Italic : FontStyles.Normal;
                TextDecorationCollection ts = (st.Underline != 0) ? TextDecorations.Underline : null;

                //st.StrikeOut!=0?
                var exts = EventExtendSection.GetSections(str);
                foreach (var ext in exts)
                {
                    if (ext.VertAlignment != null)
                    {
                        gd.VerticalAlignment = ext.VertAlignment.Value;
                    }
                    if (ext.FadeIn != null)
                    {
                        DoubleAnimation ani = new DoubleAnimation() { From = 0, To = 1, Duration = ext.FadeIn.Value };
                        Storyboard.SetTarget(ani, gd);
                        Storyboard.SetTargetProperty(ani, new PropertyPath("Image.Opacity"));
                        sb.Children.Add(ani);
                    }
                    if (ext.FadeOut != null)
                    {
                        DoubleAnimation ani = new DoubleAnimation() { From = 1, To = 0, Duration = ext.FadeOut.Value, BeginTime = item.Duration - ext.FadeOut };
                        Storyboard.SetTarget(ani, gd);
                        Storyboard.SetTargetProperty(ani, new PropertyPath("Image.Opacity"));
                        sb.Children.Add(ani);
                    }
                    if (ext.HorAlignment != null)
                    {
                        gd.HorizontalAlignment = ext.HorAlignment.Value;
                    }
                    if (ext.Point != null)
                    {
                        var tk2 = new Thickness();
                        switch (gd.VerticalAlignment)
                        {
                            case VerticalAlignment.Bottom:
                                tk2.Bottom = Container.ActualHeight - ext.Point.Value.Y * va;
                                break;
                            case VerticalAlignment.Center:
                                tk2.Top = ext.Point.Value.Y * va;
                                break;
                            case VerticalAlignment.Stretch:
                                break;
                            case VerticalAlignment.Top:
                                tk2.Top = ext.Point.Value.Y * va;
                                break;
                            default:
                                break;
                        }
                        switch (gd.HorizontalAlignment)
                        {
                            case HorizontalAlignment.Center:
                            case HorizontalAlignment.Left:
                                tk2.Left = ext.Point.Value.X * ha;
                                break;
                            case HorizontalAlignment.Right:
                                tk2.Right = Container.ActualWidth - ext.Point.Value.X * ha;
                                break;
                            case HorizontalAlignment.Stretch:
                                break;
                            default:
                                break;
                        }
                        gd.Margin = tk2;
                    }
                    txtSubtitle.Inlines.Add(new Run()
                    {
                        Text = ext.Text,
                        FontSize = st.Fontsize * va * FontScale,
                        FontStyle = fs,
                        TextDecorations = ts,
                        FontWeight = fw,
                        CharacterSpacing = (int)st.Spacing,
                        Foreground = new SolidColorBrush(GetColor(st.PrimaryColour))
                    });
                    txtSubtitle.Inlines.Add(new LineBreak());
                    txtSubtitleBack.Inlines.Add(new Run()
                    {
                        Text = ext.Text,
                        FontSize = st.Fontsize * va * FontScale,
                        FontStyle = fs,
                        TextDecorations = ts,
                        FontWeight = fw,
                        CharacterSpacing = (int)st.Spacing,
                        Foreground = new SolidColorBrush(GetColor(st.OutlineColour))
                    });
                    txtSubtitleBack.Inlines.Add(new LineBreak());
                }
            }
            WriteableBitmap bmp = new WriteableBitmap((int)(txtSubtitle.ActualWidth + 2 * lh), (int)(txtSubtitle.ActualHeight + 2 * lh));
            bmp.Render(txtSubtitleBack, new TranslateTransform() { X = 0, Y = lh });
            bmp.Render(txtSubtitleBack, new TranslateTransform() { X = 2 * lh, Y = lh });
            bmp.Render(txtSubtitleBack, new TranslateTransform() { X = lh, Y = 0 });
            bmp.Render(txtSubtitleBack, new TranslateTransform() { X = lh, Y = 2 * lh });
            bmp.Render(txtSubtitle, new TranslateTransform() { X = 1 * lh, Y = 1 * lh });
            bmp.Invalidate();
            //ReDraw(bmp, st.OutlineColour, st.PrimaryColour);
            //        bmp.Invalidate();

            gd.Source = bmp;
            if (txtSubtitle.ActualWidth <= Container.ActualWidth)
            {
                gd.Stretch = Stretch.None;
            }
            Container.Children.Add(gd);

            sb.Completed += (o, e) =>
            {
                Container.Children.Remove(gd);
                gd.Source = null;
            };
            sb.Begin();
            return gd;
        }
    }


    public abstract class SubtitleController
    {
        protected SubtitleController(Panel Container, ISubtitleReader reader)
        {
            this.Container = Container;
            SubtitleReader = reader;
        }
        public Panel Container { get; protected set; }
        public abstract FrameworkElement NewSubtitleItem(SubtitleItem item);

        public ISubtitleReader SubtitleReader { get; private set; }
    }



    public class EventExtendSection
    {
        public HorizontalAlignment? HorAlignment { get; set; }
        public VerticalAlignment? VertAlignment { get; set; }
        public double? FontSize { get; set; }
        public Color? Color { get; set; }
        public Point? Point { get; set; }
        public TimeSpan? FadeIn { get; set; }
        public TimeSpan? FadeOut { get; set; }
        public bool? Bold { get; set; }
        public bool? Underline { get; set; }
        public bool? Italic { get; set; }
        public string Text { get; set; }

        public static IEnumerable<EventExtendSection> GetSections(string Source)
        {
            string partten = @"\{\\[\w\W-[\{\}]]+\}[\w\W-[\{\}]]+"; //获取匹配项
            string partten1 = @"\{\\[\w\W-[\{\}]]+\}";  //获取控制器组
            string partten2 = @"\\[\w\W-[\\\}]]+";   //获取控制器
            string partten3 = @"\\[a-zA-Z]+";    //获取命令
            var ms = Regex.Matches(Source, partten);
            if (ms.Count > 0)
            {
                foreach (Match item in ms)
                {
                    var txt = Regex.Replace(item.Value, partten1, "");
                    //Console.WriteLine("匹配原文：{0}", item.Value);
                    //Console.WriteLine("文本：{0}", txt);
                    var ms2 = Regex.Matches(item.Value, partten2);
                    var ext = new EventExtendSection() { Text = txt };
                    foreach (Match item2 in ms2)
                    {
                        //Console.WriteLine("匹配控制器：{0}", item2.Value);
                        var ms3 = Regex.Match(item2.Value, partten3);
                        if (ms3.Success)
                        {
                            var txt2 = Regex.Replace(item2.Value, partten3, "");
                            switch (ms3.Value)
                            {
                                case @"\pos":
                                    var pt = txt2.Trim('(', ')').Split(',');
                                    ext.Point = new Point(double.Parse(pt[0]), double.Parse(pt[1]));
                                    break;
                                case @"\an":
                                    int al = int.Parse(txt2);
                                    ext.HorAlignment = ASSSubtitleController.GetHorizontalAlignment(al);
                                    ext.VertAlignment = ASSSubtitleController.GetVerticalAlignment(al);
                                    break;
                                case @"\b":
                                    ext.Bold = txt2.Trim() == "1";
                                    break;
                                case @"\i":
                                    ext.Italic = txt2.Trim() == "1";
                                    break;
                                case @"\u":
                                    ext.Underline = txt2.Trim() == "1";
                                    break;
                                case @"\c":
                                    ext.Color = ASSSubtitleController.GetColor(txt2.TrimEnd('&'));
                                    break;
                                case @"\fad":
                                    var pt2 = txt2.Trim('(', ')').Split(',');
                                    int fd1 = int.Parse(pt2[0]);
                                    int fd2 = int.Parse(pt2[0]);
                                    if (fd1 > 0)
                                    {
                                        ext.FadeIn = TimeSpan.FromMilliseconds(fd1);
                                    }
                                    if (fd2 > 0)
                                    {
                                        ext.FadeIn = TimeSpan.FromMilliseconds(fd2);
                                    }
                                    break;
                                default:
                                    break;
                            }
                        }
                    }
                    yield return ext;
                }
            }
            else
            {
                yield return new EventExtendSection() { Text = Source };
                yield break;
            }
        }
    }

}
